import numpy as np
import scipy.optimize

def Binary_OneMax(solution):
    """Binary_ solution domine - Computes the total number of ones in the candidate solution."""
    return solution.sum()

def Binary_LeadingOnes(solution):
    """Binary solution domine - Counts the number of ones in the candidate solution, starting at the beginning, until a zero is encountered."""
    loc = numpy.where(solution == 0.0)[0]
    if len(loc) > 0:
        return loc[0]
    return len(solution)

def Binary_LeadingOnesBlocks(solution):
    """Solution domine: binary - Given a block size, counts the number of strings of ones until a zero is found."""
    block_size = 3
    score = 0.0
    for idx in range(len(solution)/block_size):
        score += solution[(idx)*block_size:(idx + 1)*block_size].prod()    
    return score

def Binary_Traps(solution):
    """Solution domine: binary - It counts the number of ones in your vector, starting at the beginning, until a zero is encountered."""
    if solution.all():
        return len(solution) + 1.0
    return len(np.nonzero(solution == 0.0))

def Binary_ZeroMax(solution):
    """Solution domine: binary - It calculates the total number of zeros in a vector."""
    return len(solution) - solution.sum()

def Binary_Linear(solution):
    """Solution domine: binary - It calculates the total number of zeros in a vector."""
    return len(solution) - solution.sum()

# De Jons Real Vector Problems

def Real_Step(solution):
    """Solution domine: real - No-linkage function with a wrinkle, traditional bounds [-5.11,5.12]"""
    return -1*(6.0*len(solution) + np.sum(np.abs(solution)))

def Real_Sphere(solution):
    """Solution domine: real - This function sum the squares of the individual elements, traditional bounds [-5.11,5.12]"""
    return -1*(np.power(solution,2).sum())

def Real_Rastrigin(solution):
    """Solution domine: real - This function is essentially a large egg carton bent under a basketball, it is a combination of Sphere and a sine wave which creates a great many local optima, traditional bounds [-5.11,5.12]."""
    return -1*(10.0*len(solution) + np.sum(np.square(solution) - 10.0*np.cos(2*np.pi*solution)))

def Real_Schwefel(solution):
    """Solution domine: real - This function is deceptive in that the global minimum is geometrically distant, over the parameter space, from the next best local minima, traditional bounds [-512.03,511.97]."""
    return -1*(np.sum(-1*solution*np.sin(np.sqrt(np.abs(solution)))))

def Real_Griewank(solution):
    """Solution domine: real - The Griewank function has many widespread local minima, which are regularly distributed, traditional bounds [-600.0,600.0]."""
    positions=np.arange(len(solution))
    return -1*(1+0.00025*(np.sum(np.square(solution)))-np.prod(np.cos(solution/np.sqrt(positions+1))))

def Real_Rosenbrock(solution):
    """Solution domine: real - The Rosenbrock bounds [-2.047,2.048]."""
    return -1*(scipy.optimize.rosen(solution))